<template>
  <div id="map" class="map"></div>
  <div class="toolbar">
    <el-button type="primary" @click="handleClick">{{
      animationFlag ? "停止" : "开始"
    }}</el-button>
    <el-input v-model.number="speed"></el-input><span>速度</span>
  </div>
</template>

<script setup lang="ts">
import { Feature, Map, View } from "ol";
import { LineString, Point } from "ol/geom";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
import { get } from "ol/proj";
import { Vector as VectorSource, XYZ } from "ol/source";
import { Circle, Fill, Icon, Stroke, Style } from "ol/style";
// import iconSrc from "@/assets/image/truck.png";

const projection = get("EPSG:4326");

const layerTypeMap = {
  vector: ["vec", "cva"], // [矢量底图, 矢量注记]
  image: ["img", "cia"], // [影像底图, 影像注记]
  terrain: ["ter", "cta"], // [地形晕渲, 地形注记]
};

const map = shallowRef();
const vectorLayer = shallowRef();
const source = shallowRef<VectorSource>(new VectorSource());
const trace = ref();
const animationFlag = ref(false);
const speed = ref(50);
const lastTime = ref(Date.now());
const distance = ref(0);
const iconFeature = shallowRef();
const traceFeature = shallowRef();
const route = shallowRef();
const angle = ref(0);

onMounted(() => {
  initMap("image");
  initTraceAndFeature();
});

const initMap = (layerType = "image") => {
  const key = "替换为天地图key";

  vectorLayer.value = new VectorLayer({
    source: source.value,
    style: new Style({
      stroke: new Stroke({
        color: "rgba(228, 147, 87, 1)",
        width: 3,
      }),
    }),
  });
  // c: 经纬度投影 w: 墨卡托投影
  const matrixSet = "c";
  map.value = new Map({
    target: "map",
    layers: [
      // 底图
      new TileLayer({
        source: new XYZ({
          url: `https://t{0-7}.tianditu.gov.cn/DataServer?T=${layerTypeMap[layerType][0]}_${matrixSet}&tk=${key}&x={x}&y={y}&l={z}`,
          projection,
        }),
      }),
      // 注记
      new TileLayer({
        source: new XYZ({
          url: `https://t{0-7}.tianditu.gov.cn/DataServer?T=${layerTypeMap[layerType][1]}_${matrixSet}&tk=${key}&x={x}&y={y}&l={z}`,
          projection,
        }),
      }),
      vectorLayer.value,
    ],
    view: new View({
      center: [116.406393, 39.909006],
      projection: projection,
      zoom: 5,
      maxZoom: 17,
      minZoom: 1,
    }),
  });
};

const initTraceAndFeature = () => {
  trace.value = [
    [110, 30],
    [110.2, 30],
    [110.4, 30.2],
    [110.8, 30.4],
    [111, 31],
    [111.3, 31],
    [111.6, 31],
    [111.9, 31],
    [112, 31],
    [112.3, 31],
    [112.5, 31],
    [112.8, 31],
    [113, 31],
    [114, 31],
    [115.3, 32],
    [115.5, 32],
    [115.8, 31.8],
    [116, 31.4],
    [116.2, 31.1],
    [116.5, 30.5],
    [115, 30.2],
    [114, 29.8],
    [113, 29.6],
    [112, 29.4],
    [111, 30.2],
    [110, 30.4],
    [109, 30.6],
    [108, 31],
  ];
  angle.value = getAngle(trace.value[0], trace.value[1]);
  iconFeature.value = new Feature({
    geometry: new Point(trace.value[0]),
  });
  const icon = new Icon({
    crossOrigin: "anonymous",
    src: iconSrc,
    color: "red",
    opacity: 1,
    width: 30,
    height: 30,
    rotation: angle.value,
  });
  iconFeature.value.setStyle(
    new Style({
      image: icon,
    })
  );
  traceFeature.value = new Feature({
    geometry: new LineString(trace.value),
  });

  source.value?.addFeatures([iconFeature.value, traceFeature.value]);
  route.value = new LineString(trace.value);
};

const handleClick = () => {
  if (!animationFlag.value) {
    startAnimation();
  } else {
    stopAnimation();
  }
  animationFlag.value = !animationFlag.value;
};

const startAnimation = () => {
  lastTime.value = Date.now();
  vectorLayer.value.on("postrender", move);
  // 触发地图渲染
  const geo = iconFeature.value.getGeometry().clone();
  iconFeature.value.setGeometry(geo);
};
const move = (e) => {
  const time = e.frameState.time;
  // 时间戳差（毫秒）
  const elapsedTime = time - lastTime.value;
  // 距离(其实是比例的概念)
  distance.value = distance.value + (speed.value * elapsedTime) / 1e6;
  if (distance.value >= 1) {
    distance.value = 0;
    iconFeature.value.getGeometry().setCoordinates(trace.value[0]);
    animationFlag.value = false;
    iconFeature.value
      .getStyle()
      .getImage()
      .setRotation(getAngle(trace.value[0], trace.value[1]));
    stopAnimation();
    return;
  }
  // 保存当前时间
  lastTime.value = time;
  // 上次坐标
  const lastCoord = iconFeature.value.getGeometry().getCoordinates();
  // 获取新位置的坐标点
  const curCoord = route.value.getCoordinateAt(distance.value);
  // 设置新坐标
  iconFeature.value.getGeometry().setCoordinates(curCoord);
  // 设置角度
  iconFeature.value
    .getStyle()
    .getImage()
    .setRotation(getAngle(lastCoord, curCoord));
  // 调用地图渲染
  map.value.render();
};

const stopAnimation = () => {
  vectorLayer.value.un("postrender", move);
};

const getAngle = (point1, point2) => {
  let arc = 0;
  if (point2 && point2.length && point1 && point1.length) {
    if (
      (point2[0] - point1[0] >= 0 && point2[1] - point1[1] >= 0) ||
      (point2[0] - point1[0] < 0 && point2[1] - point1[1] > 0)
    ) {
      arc = Math.atan((point2[0] - point1[0]) / (point2[1] - point1[1]));
    } else if (
      (point2[0] - point1[0] > 0 && point2[1] - point1[1] < 0) ||
      (point2[0] - point1[0] < 0 && point2[1] - point1[1] < 0)
    ) {
      arc =
        Math.PI + Math.atan((point2[0] - point1[0]) / (point2[1] - point1[1]));
    }
  }
  return arc;
};
</script>
<style scoped lang="scss">
.map {
  width: 100%;
  height: 100%;
}
.toolbar {
  position: absolute;
  top: 20px;
  left: 100px;
  display: flex;
  justify-content: center;
  align-items: center;
  .el-input {
    width: 100px;
    margin: 0 20px;
  }
}
</style>
